package theorie;

import java.util.Vector;
import java.io.*;

public class Turing{
  /* Zustände werden mit ganzen Zahlen benannt. 1 ist der Startzustand, 0 der
     Endzustand. Zustandsnummern enden stets mit einem Punkt.
     Das Leerzeichen ist ' '.
     Eine Regel besteht aus
       vorherZustand.LesezeichenSchreibzeichenKopfbewegungNachherzustand,
       (Nach jeder Regel muss ein Komma folgen, auch nach der letzten!)
     Beispiel: 14.abN0, bedeutet von 14 bei Lesen von a schreibe ein b,
               bleibe wo du bist und gehe in den Endzustand 0.
   */
  public static void main(String[] args){
    if(args.length<2){
      System.out.println("Aufruf: java Turing  maschine     band [vv]");
      System.out.println("  oder: java Turing -maschine.tur band [vv]");
      System.out.println("v bewirkt Einzelschrittausgabe.");
      System.out.println("vv noch Farbe dazu.");
      System.exit(-1);
    }
    String maschine=args[0];
    if(maschine.startsWith("-")){
      try{
        BufferedReader br=new BufferedReader(
            new FileReader(maschine.substring(1)));
        StringBuffer m=new StringBuffer();
        while((maschine=br.readLine())!=null){
          if(maschine.length()<1||!Character.isDigit(maschine.charAt(0))) continue;
          int p=maschine.indexOf('.')+4;
          m.append(maschine.subSequence(0,maschine.indexOf(',',p)+1));
        }
        maschine=m.toString();
        System.out.println(maschine);
      } catch(Exception ex){System.out.println(ex);}
    }
    band=new StringBuffer(args[1]);
    if(args.length>=3){
      if(args[2].contains("v")) quiet=1;
      if(args[2].contains("vv")) quiet=2;
    }
    int p=-1, k, d, von, nach; char r, w;
    while(++p<maschine.length()){//erzeuge Regeln aus dem ersten String
      k=maschine.indexOf('.',p);
      von=Integer.parseInt(maschine.substring(p,k));
      r=maschine.charAt(k+3);
      d=r=='L'?-1:r=='R'?1:0;
      r=maschine.charAt(k+1);
      w=maschine.charAt(k+2);
      p=maschine.indexOf(',',k+4);
      nach=Integer.parseInt(maschine.substring(k+4,p));
      Regel.makeRegel(von, r, w, (byte)d, nach);
    }
    int zustand=1;
    int schritte=von=0;
    while(zustand!=0){
      if(quiet>0) ausgabe(von);
      schritte++;
      r=band.charAt(kopf);
      Regel regel=Regel.getRegel(zustand, r);
      if(regel==null){
        System.out.println("Keine Regel vorhanden für Zustand "+zustand
            +"\n  bei gelesenem Zeichen "+r+" an Position "+kopf);
        System.exit(-2);
      }
      zustand=regel.nach;
      band.setCharAt(kopf, regel.w);
      von=kopf;//f�r nachtr�gliche F�rbung
      kopf+=regel.d;
      if(kopf==-1 || kopf==band.length()){//links oder rechts verl�ngern!
        if(kopf==-1){
          kopf=0;
          von=1;
        }
        band.insert(kopf,' ');
      }
    }
    ausgabe(von);
    System.out.println(schritte+" Schritte, Bandlänge="+band.toString().trim().length());
  }

  public static void ausgabe(int von){
    if(quiet>1){
      StringBuffer s=new StringBuffer(band.length()+18);
      s.append(band);
      if(kopf>von){
        s.insert(kopf+1,C0);
        s.insert(kopf,C1);
        s.insert(von,C2);
      } else{
        s.insert(von+1,C0);
        s.insert(von,C2);
        s.insert(kopf,C1);
      }
      System.out.println(s);
    } else
      System.out.println(band);
  }

  public static StringBuffer band;//wird ggf. vorne oder hinten verlängert
  public static int kopf=0; //Kopfposition im Band
  public static final String C0="[0m";
  public static final String C1="[0;4m";
  public static final String C2="[0;31m";
  public static int quiet=0;
}

class Regel{
  static Vector<Regel> regeln=new Vector<Regel>(20);
  int von, nach; char r, w; byte d;

  public Regel(int von, char r, char w, byte d, int nach){
    this.von=von;
    this.r=r;
    this.w=w;
    this.d=d;
    this.nach=nach;
  }

  public static void makeRegel(int von, char r, char w, byte d, int nach){
    Regel regel=new Regel(von, r, w, d, nach);
    regeln.add(regel);
  }

  public static Regel getRegel(int von, char r){
    for(Regel regel:regeln)
      if(regel.von==von && regel.r==r) return regel;
    return null;
  }
}
